package com.meizhuang.controller;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.meizhuang.base.BaseController;
import com.meizhuang.entity.Order;
import com.meizhuang.entity.UserInfo;
import com.meizhuang.entity.enums.OrderStatusEnum;
import com.meizhuang.result.JsonResult;
import com.meizhuang.service.OrderService;
import com.meizhuang.service.UserInfoService;
import com.wechat.pay.contrib.apache.httpclient.auth.ScheduledUpdateCertificatesVerifier;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.Signature;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RestController
@Slf4j

@Api(tags = "微信支付接口")
public class PayController  extends BaseController {

    @Resource
    private RestTemplate restTemplate;
    @Resource
    private ScheduledUpdateCertificatesVerifier verifier;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private OrderService orderService;

    /**
     * 下单接口
     *  返回预支付交易会话标识。用于后续接口调用中使用，该值有效期为2小时
     *  商户系统先调用该接口在微信支付服务后台生成预支付交易单，返回正确的预支付交易会话标识后再按Native、JSAPI、APP等不同场景生成交易串调起支付
     * @return
     */
    @PostMapping(value = "/order")
    @ApiOperation(value = "统一下单接口", notes = "统一下单接口")
    public JsonResult order(@RequestBody OrderRequest orderRequest) throws Exception {
        /**
         * {
         * 	"mchid": "1900006XXX",  直连商户号 直连商户的商户号，由微信支付生成并下发。
         * 	"out_trade_no": "APP1217752501201407033233368018",
         * 	"appid": "wxb4ba3c02aa476XXX", 由微信生成的应用ID，全局唯一。请求基础下单接口时请注意APPID的应用属性，直连模式下该id应为APP应用的id。
         * 	"description": "Image形象店-深圳腾大-QQ公仔",  商品描述
         * 	"notify_url": "https://weixin.qq.com/",
         * 	"amount": {
         * 		"total": 1,
         * 		"currency": "CNY"
         *        }
         * }
         */

        Integer userSession = (Integer)super.getSession().getAttribute(UserInfo.USER_SESSION_UID);
        if(userSession == null){
            return JsonResult.buildError("请登录");
        }

        UserInfo userInfo = userInfoService.selectById(userSession);
        String orderCode = OrderUtils.getOrderCode(userInfo.getUid());

        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());

        /**
         * {
         * 	"mchid": "1900006XXX",
         * 	"out_trade_no": "APP1217752501201407033233368018",
         * 	"appid": "wxb4ba3c02aa476XXX",
         * 	"description": "Image形象店-深圳腾大-QQ公仔",
         * 	"notify_url": "https://weixin.qq.com/",
         * 	"amount": {
         * 		"total": 1,
         * 		"currency": "CNY"
         *        }
         * }
         */
        JSONObject body = new JSONObject();
        String noticeUrl = "https://api.yuanbaojia.com/wxpay/pay.action";

        body.put("mchid", "1601615594");
        body.put("appid", "wxae4d34150bd8e447");
        body.put("notify_url", noticeUrl);
        body.put("description", orderRequest.getDescription());

        JSONObject amount = new JSONObject();
        amount.put("total", orderRequest.getTotal());
        amount.put("currency", orderRequest.getCurrency());
        body.put("amount", amount);
        body.put("out_trade_no", orderCode);


        String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/app";
        if(1 == orderRequest.getPayType()) {
            //APP 支付
            url = "https://api.mch.weixin.qq.com/v3/pay/transactions/app";
        }else if (2 == orderRequest.getPayType()) {
            //小程序支付
            url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";

            /**
             * {
             * 	"mchid": "1900006XXX",
             * 	"out_trade_no": "1217752501201407033233368318",
             * 	"appid": "wxdace645e0bc2cXXX",
             * 	"description": "Image形象店-深圳腾大-QQ公仔",
             * 	"notify_url": "https://www.weixin.qq.com/wxpay/pay.php",
             * 	"amount": {
             * 		"total": 1,
             * 		"currency": "CNY"
             *        },
             * 	"payer": {
             * 		"openid": "o4GgauInH_RCEdvrrNGrntXDuXXX"
             *    }
             * }
             */
            JSONObject payer = new JSONObject();
            body.put("appid", "wxfa659ca32c6551d3");
            payer.put("openid", orderRequest.getOpenId());
            body.put("payer",payer);
        }

        HttpUrl httpUrl = HttpUrl.parse(url);

        /**
         * System.out.println(url);
         * //则将会打印出：
         * https://www.google.com/search?q=polar%20bears
         */


        final String bodyStr = body.toString();
        final String token = getToken("POST", httpUrl, bodyStr,"40E50643A15A2AA244D392E93033C3EB1844406A");

        StringBuilder builder = new StringBuilder();
        builder.append("WECHATPAY2-SHA256-RSA2048 ")
                .append(token);

        headers.add("Authorization", builder.toString());
        HttpEntity<JSONObject> formEntity = new HttpEntity(bodyStr, headers);

        try {
            /**
             * curl https://api.mch.weixin.qq.com/v3/certificates -H
             * 'Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1900009191",
             * nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",
             * signature="uOVRnA4qG/MNnYzdQxJanN+zU+lTgIcnU9BxGw5dKjK+VdEUz2FeIoC+D5sB/LN+nGzX3hfZg6r5wT1pl2ZobmIc6p0ldN7J6yDgUzbX8Uk3sD4a4eZVPTBvqNDoUqcYMlZ9uuDdCvNv4TM3c1WzsXUrExwVkI1XO5jCNbgDJ25nkT/c1gIFvqoogl7MdSFGc4W4xZsqCItnqbypR3RuGIlR9h9vlRsy7zJR9PBI83X8alLDIfR1ukt1P7tMnmogZ0cuDY8cZsd8ZlCgLadmvej58SLsIkVxFJ8XyUgx9FmutKSYTmYtWBZ0+tNvfGmbXU7cob8H/4nLBiCwIUFluw==",
             * timestamp="1554208460",
             * serial_no="1DDE55AD98ED71D6EDD4A4A16996DE7B47773A8C"'
             */
            String result = restTemplate.postForObject(url, formEntity, String.class);

            JSONObject jsonObject = JSONObject.parseObject(result);


            Date now = new Date();
            Order order = Order.builder().orderDescription(orderRequest.getDescription())
                                        .uid(Long.parseLong(userInfo.getUid().toString()))
                                        .orderId(Long.parseLong(orderCode))
                                        .orderTotal(orderRequest.getTotal())
                                        .currency(orderRequest.getCurrency())
                                        .prepayId(jsonObject.getString("prepay_id"))
                                        .payType(orderRequest.getPayType())
                                        .status(OrderStatusEnum.INIT.getValue())
                                        .openId(Strings.nullToEmpty(orderRequest.getOpenId()))
                                        .notifyUrl(noticeUrl)
                                        .ctime(now)
                                        .mtime(now)
                                        .build();

            orderService.insert(order);


            Map<String,Object> retMap = new HashMap<>();

            if(1 == orderRequest.getPayType()) { //APP支付
                String appId = "wxae4d34150bd8e447";
                String partnerid  = "1601615594";
                long timestamp = System.currentTimeMillis() / 1000;
                String nonceStr = timestamp + "";
                String packageStr = "Sign=WXPay"; //暂填写固定值Sign=WXPay

                //微信返回的支付交易会话ID，该值有效期为2小时。
                String prepayid = order.getPrepayId();

                String message =  appId + "\n"
                        + timestamp + "\n"
                        + nonceStr + "\n"
                        + prepayid + "\n";
                //	签名，使用字段appId、timeStamp、nonceStr、prepayid计算得出的签名值
                String sign = sign(message.getBytes("utf-8"));
                retMap.put("appid",appId);
                retMap.put("partnerid",partnerid);
                retMap.put("prepayid",prepayid);
                retMap.put("package",packageStr);
                retMap.put("nonceStr",nonceStr);
                retMap.put("timeStamp",timestamp);
                retMap.put("sign",sign);

            } else if (2 == orderRequest.getPayType()) {
                //小程序
                String appId = "wxfa659ca32c6551d3";
                long timestamp = System.currentTimeMillis() / 1000;
                String nonceStr = timestamp + "";
                String packageStr = String.format("prepay_id=%s",order.getPrepayId()) ;
                String signType = "RSA";

                String message =  appId + "\n"
                        + timestamp + "\n"
                        + nonceStr + "\n"
                        + packageStr + "\n";
                //	签名，使用字段appId、timeStamp、nonceStr、package计算得出的签名值
                String paySign = sign(message.getBytes("utf-8"));
                retMap.put("appId",appId);
                retMap.put("timeStamp",timestamp);
                retMap.put("nonceStr",nonceStr);
                retMap.put("package",packageStr);
                retMap.put("signType",signType);
                retMap.put("paySign",paySign);
            }

            return JsonResult.buildSuccess(retMap);
        } catch (Exception e) {
            log.error("order.error",e);
            return JsonResult.buildError(e);
        }

    }

    /**
     * 2022/09/06至2027/09/05
     * 商户证书序列号              40E50643A15A2AA244D392E93033C3EB1844406A
     * 微信平台证书序列号          5D19050C03AAB9F953793CFE39F86C1C2B0F62AB
     * @param method
     * @param url
     * @param body
     * @return
     * @throws Exception
     */
    public String getToken(String method, HttpUrl url, String body,String serialNo) throws Exception {
        long timestamp = System.currentTimeMillis() / 1000;
        String nonceStr = timestamp + "";
        String message = buildMessage(method, url, timestamp, nonceStr, body);
        String signature = sign(message.getBytes("utf-8"));

        String mchid = "1601615594";

        return "mchid=\"" + mchid + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "signature=\"" + signature + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + serialNo + "\""
                ;
    }

    public String  sign(byte[] message) throws Exception {

        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(RSAEncrypt.getPrivateKey());
        sign.update(message);

        return Base64.getEncoder().encodeToString(sign.sign());
    }

    /**
     * HTTP请求方法\n
     * URL\n
     * 请求时间戳\n
     * 请求随机串\n
     * 请求报文主体\n
     *
     * @param method
     * @param url
     * @param timestamp
     * @param nonceStr
     * @param body
     * @return
     */
    String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
        String canonicalUrl = url.encodedPath();
        if (url.encodedQuery() != null) {
            canonicalUrl += "?" + url.encodedQuery();
        }

        return method + "\n"
                + canonicalUrl + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }

    /**
     * 微信支付通过支付通知接口将用户支付成功消息通知给商户
     *
     * notice
     * 注意：
     * • 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是，当商户系统收到通知进行处理时，先检查对应业务数据的状态，
     *  并判断该通知是否已经处理。如果未处理，则再进行处理；如果已处理，则直接返回结果成功。在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱。
     * • 如果在所有通知频率后没有收到微信侧回调，商户应调用查询订单接口确认订单状态。
     *
     *
     *  特别提醒：商户系统对于开启结果通知的内容一定要做签名验证，并校验通知的信息是否与商户侧的信息一致，防止数据泄露导致出现“假通知”，造成资金损失。
     *
     * 用户支付完成后，微信会把相关支付结果和用户信息发送给商户，商户需要接收处理该消息，并返回应答。
     *
     * 对后台通知交互时，如果微信收到商户的应答不符合规范或超时，微信认为通知失败，微信会通过一定的策略定期重新发起通知，
     * 尽可能提高通知的成功率，但微信不保证通知最终能成功。（通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m）
     *
     *
     * 支付结果通知是以POST 方法访问商户设置的通知url，通知的数据以JSON 格式通过请求主体（BODY）传输。通知的数据包括了加密的支付结果详情。
     * （注：由于涉及到回调加密和解密，商户必须先设置好apiv3秘钥后才能解密回调通知，apiv3秘钥设置文档指引详见APIv3秘钥设置指引）
     *
     *
     * 下面详细描述对通知数据进行解密的流程：
     *
     * 1、用商户平台上设置的APIv3密钥【微信商户平台—>账户设置—>API安全—>设置APIv3密钥】，记为key；
     * 2、针对resource.algorithm中描述的算法（目前为AEAD_AES_256_GCM），取得对应的参数nonce和associated_data；
     * 3、使用key、nonce和associated_data，对数据密文resource.ciphertext进行解密，得到JSON形式的资源对象；
     *
     * 注： AEAD_AES_256_GCM算法的接口细节，请参考rfc5116。微信支付使用的密钥key长度为32个字节，随机串nonce长度12个字节，associated_data长度小于16个字节并可能为空字符串。
     */
    @PostMapping(value = "/wxpay/pay.action")
    @ApiOperation(value = "回调通知", notes = "回调通知")
//    public ResponseEntity.BodyBuilder payAction(@RequestBody OrderPayAction orderPayAction,HttpServletRequest request, HttpServletResponse response) throws Exception {
    public ResponseEntity.BodyBuilder payAction(HttpServletRequest request, HttpServletResponse response) throws Exception {
        try {
            //获取报文
            String body = getRequestBody(request);

            log.info("PayController.payAction.body:{}",body);
            //随机串
            String nonceStr = request.getHeader("Wechatpay-Nonce");

            //微信传递过来的签名
            String signature = request.getHeader("Wechatpay-Signature");

            //证书序列号（微信平台）
            String serialNo = request.getHeader("Wechatpay-Serial");

            //时间戳
            String timestamp = request.getHeader("Wechatpay-Timestamp");


            /**
             * 通知签名
             * 加密不能保证通知请求来自微信。微信会对发送给商户的通知进行签名，并将签名值放在通知的HTTP头Wechatpay-Signature。
             * 商户应当验证签名，以确认请求来自微信，而不是其他的第三方。签名验证的算法请参考 《微信支付API v3签名验证》。
             */


            /**
             * {
             *     "data":[
             *         {
             *             "effective_time":"2020-08-05T19:04:31+08:00",
             *             "encrypt_certificate":{
             *                 "algorithm":"AEAD_AES_256_GCM",
             *                 "associated_data":"certificate",
             *                 "ciphertext":"V4EQJv2+BTrlCW7AKCuxSDa7doxjzWN+P2jJpqsQW3pjctG0uWk0u5jq8VkAj13B4Lz9qgzW9Cwg/IUsIbJvCJnHnN34AHepj+vHgyafLBqu/bxhQdsS6Fe0B/rcQfzATzzSOz4Djg5iKab/2531fyQmQv+XEbNT1zktQ2XZ9BkZAsJKLcmSJxm24xSutGsZ9iPc8GsFEO6VMs5XUFCbXVs7f2SZVhs9Xh13FzvWLMyHTb2T8gHyzggsm+JitYIVeeS7c0aCBjfp4b1Y0gtHSzmROky2GYtvfFOdPZcM+/XdpDoPwqHoQvgcFDlJVF1BrZkLM/JmAVc6saK+MkQgvXVvkn0vFaylu+uUkDmz/7ZjcFD8vbwFSIAP5OfzPiqiJAq7IUL+OS+If12jidsW0rI33s9bx6G237WHBnvArt3IDUIlHXMXkbSm4rK5ssgPfw+B6Kq6SgyL3jy9Ttu7YI5eydotwnko+HkLICbvVsSyio8tF4HdE2y475IwnTyw+R2hFficoXnJ4/8SNYvBPhkNOoCZsLxtsE3FLHdF6/m2W0yFhHes8bp14vEHTRRK1KPxzODDUsiEkbFdgXorLTS3Zv4UNhbidXGmzeYgDNnarKFhOx5PBHNDFx2P7uVj0fG+x241deed2vfvQ+j1COwpLBdq30CB/p6kaA81ePkd53U2+K0eY2ST9Tte6CPBzLax+Sd2ToozqsIHujj1ORTTfq9KmB0Fa9fAFBaHen8nnmIp6I3ZBhmC0M3TJXzv+ppRD6JJsviDhStokP8zD2csHO+0J8Ko89bFxIUbDSS2+uf6Ro22DrkQMIz+yvYe8iXjbMvEzs5hGmsSq/u25qyIZRrF5um1ryZ8ArSQc75cv/NUXhRCwO/qBjdwJiVArVvmFbiSnn9wtjD3nxbiusqtR9bSDUKjbltO3kROFy4yRYywcb9JdorGk0TfZCRZrdIuff/8d03/hGF4ZXRSeZmZX6ft12oL1KXCFgzhxNIkD5qchCczC9AZSVwnr0fYMt5I533JYdnAkm6J/F8WTHzxJGuitZTM1eawV/1WkyN1zW4B5n2oAw9OtOy3AvMlgO8JqilHZn9amkk7zq1eAH361piMbHJXIt9rGkLG1ta7q6jOVpRmY33mPF435heUArKJbJZUC/bwaac02CgUmy4tSNj3jBKHnja9FP0O8xwSAOYd3pKDyeh8d+WXHlghaqW3pCD5YJ1sqKVnpF65ruIJiO7yGIUeBccYlOnDoEXcxdGQkbJLBXdqarnX9Q9TAytVIcNcEOn40/VgfzLyG4jgqypD04nrS7NaZ7ctx8H16ciyrmHHEhhZq8MpBbf5YBUFIJQGqsi3ygJ6NGrEHufsmnZqIH8jde7axBkFbd7bipu3Lt0C+4I2cqZFH/Ow2GcrjlbQuV2Uzugw+lLfIME1u0awaE9vl86h1BqLM3TKuKEMpS7MzlysYkrJMMN6vRaQnqvdC88M/Z/xyeb++OZoviPwnYdghpqNZtYn9vV3q+UlNebu7y0MQ6mlnwXbMJUtltimhjZwD/5RbYHexEVaw+8HjmmmT6cwyreg5Zj/I8lTawTYqN2yAhP5HFsUXMGjOIi8M5CdlMK1n9thmZqrRsWuSyd36egC/U5rs0d+PdcVW4S/uG30ZUwZKB+E7keP/wzg4iq6QpOGpokEzVLSz3xsQXmtKDXIoiXArEcvliu/oY57kek17EbTZRxicIj5IH87Nl8Ty1JU0xPmRUDHPv+zZO23tfZ8ebyycS62img1CBZ9SLcsx8sk0pAnxazfc8e2G8GJfgNEP08uMd3SJmC1SV84OXtf/YQ8la27E7E1HiI9Hn1yHIVDvXFUS0bc8sEvkhM64ZWgu3kLUy95ZefXZg==",
             *                 "nonce":"b2520c3b9a16"
             *             },
             *             "expire_time":"2025-08-04T19:04:31+08:00",
             *             "serial_no":"5D19050C03AAB9F953793CFE39F86C1C2B0F62AB"
             *         }
             *     ]
             * }
             */


            String url = "https://api.mch.weixin.qq.com/v3/certificates";

            HttpUrl httpUrl = HttpUrl.parse(url);
            final String token = getToken("GET", httpUrl, "", "40E50643A15A2AA244D392E93033C3EB1844406A");

            HttpHeaders headers = new HttpHeaders();
            MediaType type = MediaType.parseMediaType("application/json");
            headers.setContentType(type);
            headers.add("Accept", MediaType.APPLICATION_JSON.toString());

            StringBuilder builder = new StringBuilder();
            builder.append("WECHATPAY2-SHA256-RSA2048 ").append(token);

            headers.add("Authorization", builder.toString());
            headers.add("User-Agent", "okhttp\\/3.12.12");
            HttpEntity<JSONObject> formEntity = new HttpEntity("", headers);
            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, formEntity, String.class);
            final String result = responseEntity.getBody();

            log.info("PayController.payAction.result:{}",result);
            final Map map = JSONObject.parseObject(result, Map.class);

            List<Map> dataList = (List<Map>) map.get("data");

            //微信平台证书序列号
            String weChatSerialNo = null;

            if(null != dataList){

                for(Map<String,Object> dataMap:dataList){
                    //微信平台证书过期时间
                    String expireTime = (String) dataMap.get("expire_time");
                    Date now = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");

                    final Date parse = sdf.parse(expireTime);

                    if (now.after(parse)) {
                        continue;
                    }
                    //微信平台证书序列号
                    weChatSerialNo = (String) dataMap.get("serial_no");
                    break;
                }

            }


            if(!Strings.isNullOrEmpty(weChatSerialNo)) {
                //微信支付API v3使用微信支付 的平台私钥（不是商户私钥 ）进行应答签名。相应的，商户的技术人员应使用微信支付平台证书中的公钥验签。目前平台证书只提供API进行下载，
                //再次提醒，应答和回调的签名验证使用的是 微信支付平台证书，不是商户API证书。使用商户API证书是验证不过的。

                //构造签名串
                //应答时间戳\n
                //应答随机串\n
                //应答报文主体\n
                String signStr = Stream.of(timestamp, nonceStr, body).collect(Collectors.joining("\n", "", "\n"));
                log.info("PayController.payAction.signStr:{}",signStr);
                //验证签名是否通过
//                boolean verifiedSign = verifiedSign(weChatSerialNo, signStr, signature);
//                log.info("PayController.payAction.verifiedSign:{}",verifiedSign);
//                if(verifiedSign){
                    //解密数据
                    String plainBody = decryptBody(body);

                    log.info("解密后的明文:{}",plainBody);
                    /**
                     * {
                     *     "transaction_id":"1217752501201407033233368018",
                     *     "amount":{
                     *         "payer_total":100,
                     *         "total":100,
                     *         "currency":"CNY",
                     *         "payer_currency":"CNY"
                     *     },
                     *     "mchid":"1230000109",
                     *     "trade_state":"SUCCESS",
                     *     "bank_type":"CMC",
                     *     "promotion_detail":[
                     *         {
                     *             "amount":100,
                     *             "wechatpay_contribute":0,
                     *             "coupon_id":"109519",
                     *             "scope":"GLOBAL",
                     *             "merchant_contribute":0,
                     *             "name":"单品惠-6",
                     *             "other_contribute":0,
                     *             "currency":"CNY",
                     *             "stock_id":"931386",
                     *             "goods_detail":[
                     *                 {
                     *                     "goods_remark":"商品备注信息",
                     *                     "quantity":1,
                     *                     "discount_amount":1,
                     *                     "goods_id":"M1006",
                     *                     "unit_price":100
                     *                 },
                     *                 {
                     *                     "goods_remark":"商品备注信息",
                     *                     "quantity":1,
                     *                     "discount_amount":1,
                     *                     "goods_id":"M1006",
                     *                     "unit_price":100
                     *                 }
                     *             ]
                     *         },
                     *         {
                     *             "amount":100,
                     *             "wechatpay_contribute":0,
                     *             "coupon_id":"109519",
                     *             "scope":"GLOBAL",
                     *             "merchant_contribute":0,
                     *             "name":"单品惠-6",
                     *             "other_contribute":0,
                     *             "currency":"CNY",
                     *             "stock_id":"931386",
                     *             "goods_detail":[
                     *                 {
                     *                     "goods_remark":"商品备注信息",
                     *                     "quantity":1,
                     *                     "discount_amount":1,
                     *                     "goods_id":"M1006",
                     *                     "unit_price":100
                     *                 },
                     *                 {
                     *                     "goods_remark":"商品备注信息",
                     *                     "quantity":1,
                     *                     "discount_amount":1,
                     *                     "goods_id":"M1006",
                     *                     "unit_price":100
                     *                 }
                     *             ]
                     *         }
                     *     ],
                     *     "success_time":"2018-06-08T10:34:56+08:00",
                     *     "payer":{
                     *         "openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"
                     *     },
                     *     "out_trade_no":"1217752501201407033233368018",
                     *     "appid":"wxd678efh567hg6787",
                     *     "trade_state_desc":"支付成功",
                     *     "trade_type":"MICROPAY",
                     *     "attach":"自定义数据",
                     *     "scene_info":{
                     *         "device_id":"013467007045764"
                     *     }
                     * }
                     */
                    Map<String, String> paramsMap = convertWechatPayMsgToMap(plainBody);
                    log.info("PayController.payAction.paramsMap:{}",paramsMap.values());
                    final String tradeNo = paramsMap.get("out_trade_no");
                    if(!Strings.isNullOrEmpty(tradeNo)) {
                        log.info("PayController.payAction.tradeNo:{}",tradeNo);
                        final Order order = orderService.selectById(tradeNo);

                        if(null != order) {
                            log.info("PayController.payAction.order:{}",order);
                            final Integer status = order.getStatus();

                            if (status == OrderStatusEnum.SUCCESS.getValue() ){
                                //响应微信
                                map.put("code", "SUCCESS");
                                map.put("message", "成功");

                                final ResponseEntity.BodyBuilder bodyBuilder = ResponseEntity.status(200);
                                bodyBuilder.body(map);
                                return bodyBuilder;
                            }

                            final OrderStatusEnum orderStatusEnum = OrderStatusEnum.getOrderStatusName(paramsMap.get("trade_state"));

                            order.setStatus(orderStatusEnum.getValue());

                            final boolean updateById = orderService.updateById(order);
                            log.info("PayController.payAction.updateById:{}",updateById);
                            if(updateById) {

                                //响应微信
                                map.put("code", "SUCCESS");
                                map.put("message", "成功");

                                final ResponseEntity.BodyBuilder bodyBuilder = ResponseEntity.status(200);
                                bodyBuilder.body(map);
                                return bodyBuilder;

                            }

                        }

                    }

                }
//            }

        }catch (Exception e) {
            log.error("payAction.error",e);
        }


        ResponseEntity.BodyBuilder bodyBuilder = ResponseEntity.badRequest();
        Map<String,Object> retMap =new HashMap<>();
        retMap.put("code","FAIL");
        retMap.put("message","失败");
        bodyBuilder.body(retMap);
        return bodyBuilder;
    }




    /**
     * 读取请求数据流
     *
     * @param request
     * @return
     */
    private String getRequestBody(HttpServletRequest request) {

        StringBuffer sb = new StringBuffer();

        try (ServletInputStream inputStream = request.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        ) {
            String line;

            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }

        } catch (IOException e) {
            log.error("读取数据流异常:{}", e);
        }

        return sb.toString();
    }

    /**
     * 验证签名
     *
     * @param serialNo  微信平台-证书序列号
     * @param signStr   自己组装的签名串
     * @param signature 微信返回的签名
     * @return
     * @throws UnsupportedEncodingException
     */
    private boolean verifiedSign(String serialNo, String signStr, String signature) throws UnsupportedEncodingException {
        return verifier.verify(serialNo, signStr.getBytes("utf-8"), signature);
    }

    /**
     * 解密body的密文
     *
     * "resource": {
     *         "original_type": "transaction",
     *         "algorithm": "AEAD_AES_256_GCM",
     *         "ciphertext": "",
     *         "associated_data": "",
     *         "nonce": ""
     *     }
     *
     * @param body
     * @return
     */



    /**
     * 商户对resource对象进行解密后，得到的资源对象示例
     *  {
     *     "transaction_id":"1217752501201407033233368018",
     *     "amount":{
     *         "payer_total":100,
     *         "total":100,
     *         "currency":"CNY",
     *         "payer_currency":"CNY"
     *     },
     *     "mchid":"1230000109",
     *     "trade_state":"SUCCESS",
     *     "bank_type":"CMC",
     *     "promotion_detail":[
     *         {
     *             "amount":100,
     *             "wechatpay_contribute":0,
     *             "coupon_id":"109519",
     *             "scope":"GLOBAL",
     *             "merchant_contribute":0,
     *             "name":"单品惠-6",
     *             "other_contribute":0,
     *             "currency":"CNY",
     *             "stock_id":"931386",
     *             "goods_detail":[
     *                 {
     *                     "goods_remark":"商品备注信息",
     *                     "quantity":1,
     *                     "discount_amount":1,
     *                     "goods_id":"M1006",
     *                     "unit_price":100
     *                 },
     *                 {
     *                     "goods_remark":"商品备注信息",
     *                     "quantity":1,
     *                     "discount_amount":1,
     *                     "goods_id":"M1006",
     *                     "unit_price":100
     *                 }
     *             ]
     *         },
     *         {
     *             "amount":100,
     *             "wechatpay_contribute":0,
     *             "coupon_id":"109519",
     *             "scope":"GLOBAL",
     *             "merchant_contribute":0,
     *             "name":"单品惠-6",
     *             "other_contribute":0,
     *             "currency":"CNY",
     *             "stock_id":"931386",
     *             "goods_detail":[
     *                 {
     *                     "goods_remark":"商品备注信息",
     *                     "quantity":1,
     *                     "discount_amount":1,
     *                     "goods_id":"M1006",
     *                     "unit_price":100
     *                 },
     *                 {
     *                     "goods_remark":"商品备注信息",
     *                     "quantity":1,
     *                     "discount_amount":1,
     *                     "goods_id":"M1006",
     *                     "unit_price":100
     *                 }
     *             ]
     *         }
     *     ],
     *     "success_time":"2018-06-08T10:34:56+08:00",
     *     "payer":{
     *         "openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"
     *     },
     *     "out_trade_no":"1217752501201407033233368018",
     *     "appid":"wxd678efh567hg6787",
     *     "trade_state_desc":"支付成功",
     *     "trade_type":"MICROPAY",
     *     "attach":"自定义数据",
     *     "scene_info":{
     *         "device_id":"013467007045764"
     *     }
     * }
     */

    private String decryptBody(String body) throws IOException, GeneralSecurityException {
        /**
         * V3密钥  yuanbaojia123456yuanbaojia123456
         */

        String apiV3Key = "yuanbaojia123456yuanbaojia123456";

        AesUtil aesUtil = new AesUtil(apiV3Key.getBytes("utf-8"));

        JSONObject object = JSONObject.parseObject(body);
        JSONObject resource = object.getJSONObject("resource");
        String ciphertext = resource.getString("ciphertext");
        String associatedData = resource.getString("associated_data");
        String nonce = resource.getString("nonce");

        //final String body = aesUtil.decryptToString(orderResource.getAssociatedData().getBytes(), orderResource.getNonce().getBytes(), orderResource.getCiphertext());
        return aesUtil.decryptToString(associatedData.getBytes("utf-8"),nonce.getBytes("utf-8"),ciphertext);

    }

    /**
     * 转换body为map
     * @param plainBody
     * @return
     */
    private Map<String,String> convertWechatPayMsgToMap(String plainBody){

        Map<String,String> paramsMap = new HashMap<>(2);

        JSONObject jsonObject = JSONObject.parseObject(plainBody);

        //商户订单号
        paramsMap.put("out_trade_no",jsonObject.getString("out_trade_no"));

        //交易状态
        paramsMap.put("trade_state",jsonObject.getString("trade_state"));

        //附加数据
//        paramsMap.put("account_no",jsonObject.getJSONObject("attach").getString("accountNo"));

        return paramsMap;

    }

    @GetMapping(value = "/order/{orderNo}")
    @ApiOperation(value = "查询订单状态", notes = "查询订单状态")
    public JsonResult queryOrderStatus(@PathVariable("orderNo") String orderNo) throws Exception {

        Integer userSession = (Integer)super.getSession().getAttribute(UserInfo.USER_SESSION_UID);
        if(userSession == null){
            return JsonResult.buildError("请登录");
        }

        final Order order = orderService.selectById(orderNo);


        return JsonResult.buildSuccess(order);
    }
}